package de.fuberlin.inf.alp2;

import de.fuberlin.inf.alp2.utils.*;

/**
 * This class has been implemented within the scope of the first exercise of the
 * lecture <i>"Algorithmen und Programmierung 2 - Objektorientierte
 * Programmierung"</i>.
 * Rules:
 * <ul>
 * 		<li>the compiler mustn't throw errors or warnings</li>
 * 		<li>the program has to be executable</li>
 * 		<li>do not pack the files in RAR format</li>
 * 		<li>hand it in by mail (KRudolph@mi.fu-berlin.de) and in printed
 *          form</li>
 * 		<li><a href="http://page.mi.fu-berlin.de/krudolph">Homepage</a></li>
 * 		<li> program and annotate in English</li>
 * </ul>
 * @author stefanr
 */
public class Smod {
	public static void main(String[] args) {
		int x = ConsoleInput.readInt("Type in x value", "The entered value " +
				"could not be converted to int.");
		int y = 0;
		while (y == 0)
		{
			y = ConsoleInput.readInt("Type in y value", "The entered value " +
					"could not be converted to int.");
			if (y == 0)
				System.out.println("Sorry, but y must not be 0 due to being " +
						"used as divisor.");
		}
		
		System.out.println("" + x + " % " + y + " = " + getRemainder_2a(x, y));
		try {
			System.out.println("Greatest common divisor of " + x + " and " + y +
					" is " + gcd_3(x, y));
		}
		catch (IllegalArgumentException exc)
		{
			System.out.println(exc.getMessage());
		}
	}
	
	
	/**
	 * According to task 2a we were supposed to implement the Haskell-Algorithm
	 * for quick evaluation of modulo in Java.
	 * @param dividend
	 * @param divisor
	 * @return The remainder of integer division.
	 */
	public static long getRemainder_2a(long dividend, long divisor) {
		if (dividend < 0)
			return (-1) * getRemainder_2a((-1) * dividend, divisor);
		if (divisor < 0)
			return divisor + getRemainder_2a(dividend, (-1) * divisor);
		if (dividend >= (2*divisor))
			return getRemainder_2a((getRemainder_2a(dividend, 2*divisor)),
					divisor);
		if (dividend >= divisor)
			return getRemainder_2a(dividend - divisor, divisor);
		return dividend;
	}
	
	/**
	 * According to task 2c we were supposed to implement the ternary operator.
	 * @param x The dividend.
	 * @param y The divisor.
	 * @return The remainder of integer division.
	 */
	public static int smod_2c(int x, int y) {
		return (x < y) ? x : smod_2c (x-y, y);
	}
	
	/**
	 * The function gcd evaluates the greatest common divisor of both passed
	 * integers.
	 * @param x The first integer.
	 * @param y The second integer.
	 * @return The greatest common divisor of both passed integers.
	 * @throws IllegalArgumentException if both arguments are equal to 0.
	 */
	public static int gcd_3(int x, int y) throws IllegalArgumentException {
		int x_abs = Math.abs(x);
		int y_abs = Math.abs(y);
		if ((0 == x) &&  (0 == y))
			throw new IllegalArgumentException("No gcd for values 0 and 0!");
		if (0 == x)
			return y_abs;
		if (0 == y)
			return x_abs;
		
		if (0 == (x % y))
			return y_abs;
		if (0 == (y % x))
			return x_abs;
		int min = (x_abs < y_abs) ? x_abs : y_abs;
		int gcd = 1;
		for (int i = 2; i <= min/2; i++) {
			if ((0 == (x % i)) && (0 == (y % i)))
				gcd = i;
		}
		return gcd;
	}

}
